﻿/***************************************************************************
 *
 * Copyright (c) 2022 str2num.com, Inc. All Rights Reserved
 * $Id$
 *
 **************************************************************************/

/**
 * @file udp_port.h
 * @author str2num
 * @version $Revision$
 * @brief
 *
 **/

#ifndef ICE_UDP_PORT_H_
#define ICE_UDP_PORT_H_

#include <string>
#include <vector>
#include <map>

#include <rtc_base/socket_address.h>
#include <rtc_base/thread.h>
#include <rtc_base/async_udp_socket.h>

#if defined(ICE_POSIX)
#include "ice/base/linux/event_loop.h"
#endif

#include "base/network.h"
#include "base/linux/async_udp_socket.h"
#include "ice/ice_def.h"
#include "ice/ice_credentials.h"
#include "ice/candidate.h"
#include "ice/stun.h"

namespace ice
{

        class IceConnection;

        typedef std::map<rtc::SocketAddress, IceConnection *> AddressMap;

        class UDPPort : public sigslot::has_slots<>
        {
        public:
                UDPPort(EventLoop *el,
                        const std::string &transport_name,
                        int component,
                        IceParameters ice_params);

                ~UDPPort();

                std::string ice_ufrag() { return ice_params_.ice_ufrag; }
                std::string ice_pwd() { return ice_params_.ice_pwd; }

                const std::string &transport_name() { return transport_name_; }
                int component() { return component_; }
                const rtc::SocketAddress &local_addr() { return local_addr_; }
                const std::vector<Candidate> &candidates() { return candidates_; }

                IceRole ice_role() { return ice_role_; }
                void set_ice_role(IceRole role) { ice_role_ = role; }

                int CreateIceCandidate(Network *network, int min_port, int max_port, Candidate &c);
                bool GetStunMessage(const char *data, size_t len,
                                    const rtc::SocketAddress &addr,
                                    std::unique_ptr<StunMessage> *out_msg,
                                    std::string *out_username);
                void SendBindingErrorResponse(StunMessage *stun_msg,
                                              const rtc::SocketAddress &addr,
                                              int err_code,
                                              const std::string &reason);
                IceConnection *CreateConnection(const Candidate &candidate);
                IceConnection *GetConnection(const rtc::SocketAddress &addr);
                void CreateStunUserName(const std::string &remote_username,
                                        std::string *stun_attr_username);

                int SendTo(const char *buf, size_t len, const rtc::SocketAddress &addr);

                std::string ToString();

                sigslot::signal4<UDPPort *, const rtc::SocketAddress &, StunMessage *, const std::string &>
                    SignalUnknownAddress;

        private:
                int BindSocket(rtc::Socket *socket,
                               const rtc::SocketAddress &local_address,
                               uint16_t min_port,
                               uint16_t max_port);
                void OnReadPacket(AsyncUdpSocket *socket, const char *buf, size_t size,
                                  const rtc::SocketAddress &addr, const int64_t &ts);
                bool ParseStunUserName(StunMessage *stun_msg, std::string *local_ufrag,
                                       std::string *remote_frag);

        private:
                EventLoop *el_;
                std::unique_ptr<AsyncUdpSocket> async_socket_;
                int socket_ = -1;

                std::string transport_name_;
                int component_;
                IceParameters ice_params_;
                IceRole ice_role_ = IceRole::ICEROLE_UNKNOWN;
                rtc::SocketAddress local_addr_;
                std::vector<Candidate> candidates_;
                AddressMap connections_;
        };

} // namespace ice

#endif // ICE_UDP_PORT_H_
